package ru.hangman.donkeykong.persons;

import java.util.Hashtable;

import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import ru.hangman.donkeykong.logic.LevelRepresentation;
import ru.hangman.donkeykong.logic.LevelRepresentation.PointDescription;

import android.graphics.Point;

public class DonkeyKong extends DonkeyKongPerson {

	public enum States {
		Waiting,
		Walking,
		Hided
	}
	
	public enum Direction {
		Left,
		Right
	}
	
	private States _currentState = States.Hided;
	private Hashtable<States, Integer> statesToIdHash = new Hashtable<States, Integer>();
	private Direction _currentDirection;
	private int _maximumOffset = 0;
	final private int _walkingStepHeight = 5;	//!< Step height in walking state.
	
	/** 
	 * Current offset for scene.
	 * This used then determine where the person.
	 */
	int _sceneOffset = 0;	
	
	public DonkeyKong(BaseGameActivity activity) {
		super(activity);
		statesToIdHash.put(States.Walking, initTexture(256, 256, "donkeykong_walking_right.png", 4, 4, 50, new Point(0, 7)));
		statesToIdHash.put(States.Waiting, initTexture(512, 1024, "donkeykong_waiting_right.png", 8, 16, 150, new Point(0, 0)));
		
		_currentDirection = Direction.Right;
		
		setState(DonkeyKong.States.Waiting);
	}
	
	public void pullToLeft() {
		Direction dir = getDirection();
		switch(_currentState) {
		case Waiting:
			if(dir.equals(Direction.Right)) {
				setDirection(Direction.Left);
				setState(States.Walking);
			}
			else if(dir.equals(Direction.Left)) {
				// Begin walking left.
				setState(States.Walking);
			}
			break;
		case Walking:
			if(dir.equals(Direction.Right))
				setDirection(Direction.Left);
			break;
		}
	}
	
	public void pullToRight() {
		Direction dir = getDirection();
		switch(_currentState) {
		case Waiting:
			if(dir.equals(Direction.Left)) {
				setDirection(Direction.Right);
				setState(States.Walking);
			}
			else if(dir.equals(Direction.Right)) {
				// Begin walking right.
				setState(States.Walking);
			}
			break;
		case Walking:
			if(dir.equals(Direction.Left))
				setDirection(Direction.Right);
			break;
		}
	}

	/**
	 * Stop donkey kong.
	 */
	public void stop() {
		setState(States.Waiting);
	}
	
	public void update(Scene scene) {
		Integer id = statesToIdHash.get(_currentState);
		if(id == null)
			return;
		setId(id);
		redraw(scene);
	}
	
	public void setMaximumOffset(int maximumOffset) {
		_maximumOffset = maximumOffset;
	}
	
	private void setState(States state) {
		if(state.equals(_currentState)) 
			return;
		_currentState = state;
	}

	private void setDirection(Direction direction) {
		_currentDirection = direction;
		turnFlippingOn(_currentDirection.equals(Direction.Left));
	}
	
	private Direction getDirection() {
		return _currentDirection;
	}

	public boolean setLastUpdateTime(float secondsElapsed, LevelRepresentation level, int screenOffset) {
		float sign = 1.0f;
		if(getDirection().equals(Direction.Left))
			sign = -1.0f;
		if(_currentState.equals(States.Walking)) {
			_sceneOffset = _sceneOffset + Math.round(sign*100.0f*secondsElapsed);
			if(_sceneOffset < 0)
				_sceneOffset = 0;
			else if((_maximumOffset != 0) && (_sceneOffset >= _maximumOffset))
				_sceneOffset = _maximumOffset;
			
			// Analyze possibilities to move.
			Point currentPosition = getCurrentPosition();
			currentPosition.x = _sceneOffset;
			LevelRepresentation.PointDescription pointDesc = level.getFixedPointFor(currentPosition);
			return processStepPointDescription(currentPosition, pointDesc, screenOffset);			
		}
		return false;
	}
	
    /**
     * Get scent offset.
     * @return Offset.
     */
    public int getSceneOffset() {
    	return _sceneOffset;
    }
    
    /**
     * Set scene offset.
     * @param offset Offset.
     */
    public void setSceneOffset(int offset) {
    	_sceneOffset = offset;
    }

	@Override
	public boolean processStepPointDescription(Point sourcePoint,
			PointDescription pointDescription, int screenOffset) {
		if(pointDescription.getPointType() == LevelRepresentation.PointType.Fixed) {
			Point pos = pointDescription.getPoint();
			if(pointDescription.getSurfaceType() == LevelRepresentation.SurfaceTypes.Normal_surface) {
				// Surface is normal to moving.
				if(_currentState == States.Walking) {
					if((sourcePoint.y > pos.y) && ((sourcePoint.y - pos.y) > _walkingStepHeight)) {
						// We going up and could not step up.
						stop();
						Point point = sourcePoint;
						if(screenOffset >= 0)
							point.x = screenOffset; 
						setNewPosition(point);
						return true;
					}
					else if((sourcePoint.y < pos.y) && ((pos.y - sourcePoint.y) > _walkingStepHeight)) {
						// We need to fall.
						if(screenOffset >= 0)
							pos.x = screenOffset;
						setNewPosition(pos);
						return true;
					}
					else {
						if(screenOffset >= 0)
							pos.x = screenOffset;
						setNewPosition(pos);
						return true;
					}
				}
				else if(_currentState == States.Waiting) {
					if((sourcePoint.y < pos.y) && ((pos.y - sourcePoint.y) > _walkingStepHeight)) {
						// We need to fall.
						if(screenOffset >= 0)
							pos.x = screenOffset;
						setNewPosition(pos);
						return true;
					}
					else {
						if(screenOffset >= 0)
							pos.x = screenOffset;
						setNewPosition(pos);
						return true;
					}
				}
			}
			return false;
		}
		else {
			//TODO Kong must be falled.
			return false;
		}
	}	
}
